Last week’s exercise

Minimal working answer

# Load packages
pacman::p_load(ggspatial, sf, tidyverse)

# Load data
attacks <- read_csv("https://mpjashby.github.io/crimemappingdata/london_attacks.csv") |>
  st_as_sf(coords = c("longitude", "latitude"), crs = "EPSG:4326")

# Plot the map
ggplot(attacks) +
  annotation_map_tile(type = "osm", zoomin = 0, progress = "none") +
  geom_sf_label(aes(label = description), hjust = 1, size = 2.25) +
  geom_sf(colour = "mediumblue", size = 2) +
  scale_x_continuous(expand = expansion(mult = 0.5)) +
  scale_y_continuous(expand = expansion(mult = 0.1)) +
  labs(
    title = "Fatal terrorist attacks in London, 2000 to 2018",
    caption = "Background map by OpenStreetMap"
  ) +
  theme_void()

Minimal working answer

Permanent vs. temporary code

Permanent code

Code needed to complete a task, e.g. make a map

e.g. read_csv() to load a dataset

Temporary code

Code needed only to develop the code needed to complete a task

e.g. head(attacks) to find names of columns in a dataset

🚫 No temporary code in R script files

  • col_names()
  • excel_names()
  • head()
  • install.packages()
  • learncrimemapping::check_code()
  • names()
  • show()
  • str()

😎 Run temporary code in the R console

  • col_names()
  • excel_names()
  • head()
  • install.packages()
  • learncrimemapping::check_code()
  • names()
  • show()
  • str()

Book chapters show where to run each piece of code:

Permanent code to go in a script:

chapter_02.R
attacks <- read_csv("https://mpjashby.github.io/crimemappingdata/london_attacks.csv")

Temporary code to go in the R Console:

R Console
head(attacks)

🚫 Don’t load packages part-way through scripts

pacman::p_load(tidyverse)

attacks <- read_csv("https://mpjashby.github.io/crimemappingdata/london_attacks.csv")

pacman::p_load(sf)

attacks_sf <- st_as_sf(
  attacks, 
  coords = c("longitude", "latitude"), 
  crs = "EPSG:4326"
)

😎 Load all the packages at the start of the script

pacman::p_load(sf, tidyverse)

attacks <- read_csv("https://mpjashby.github.io/crimemappingdata/london_attacks.csv")

attacks_sf <- st_as_sf(
  attacks, 
  coords = c("longitude", "latitude"), 
  crs = "EPSG:4326"
)

🚫 No local file paths

readr::read_csv("/Users/John Smith/Crime Mapping/downtown_homicides.csv")
Error: '/Users/John Smith/Crime Mapping/downtown_homicides.csv' does not exist.
readr::read_csv("Crime Mapping/Week 1/downtown_homicides.csv")
Error: 'Crime Mapping/Week 1/downtown_homicides.csv' does not exist in current working directory ('/Users/mattashby/Documents/Crime Mapping Book/lectures').

😎 Download data inside your script

readr::read_csv("https://mpjashby.github.io/crimemappingdata/london_attacks.csv")
# A tibble: 8 × 4
  date       latitude longitude description                                     
  <date>        <dbl>     <dbl> <chr>                                           
1 2005-07-07     51.5   -0.0813 Suicide bomb exploded on train, killing 7       
2 2005-07-07     51.5   -0.168  Suicide bomb exploded on train, killing 6       
3 2005-07-07     51.5   -0.124  Suicide bomb exploded on train, killing 26      
4 2005-07-07     51.5   -0.129  Suicide bomb exploded on bus, killing 13        
5 2013-05-22     51.5    0.0623 Soldier fatally stabbed                         
6 2017-03-22     51.5   -0.122  Car driven at pedestrians and people stabbed, k…
7 2017-06-03     51.5   -0.0878 Van driven at pedestrians and people stabbed, k…
8 2017-06-19     51.6   -0.108  Van driven at pedestrians, killing 1            

⚠️ Copy/paste with care: objects may not exist

# Load the R packages we need to analyse this data
pacman::p_load(ggspatial, sf, tidyverse)

# Download the data directly from a URL and store it as an object
attacks <- read_csv("https://mpjashby.github.io/crimemappingdata/london_attacks.csv") |>
  st_as_sf(coords = c("longitude", "latitude"), crs = "EPSG:4326")

# Plot the map
ggplot(homicides_sf_trans)
Error: object 'homicides_sf_trans' not found

⚠️ Copy/paste with care: different maps need different choices

# Transform the data to a co-ordinate reference system for the state of Georgia
fatal_terrorist_sf_trans <- st_transform(fatal_terrorist_sf, "EPSG:26967")

⚠️ Copy/paste with care: different maps need different choices

# Transform the data to a co-ordinate reference system for the city of London
fatal_terrorist_sf_trans <- st_transform(fatal_terrorist_sf, "EPSG:26967")

😎 Copy/paste with care: different maps need different choices

# Transform the data to a co-ordinate reference system for the UK
fatal_terrorist_sf_trans <- st_transform(fatal_terrorist_sf, "EPSG:27700")

🚫 Don’t use zoom in annotation_map_tile()

# Load the R packages we need to analyse this data
pacman::p_load(ggspatial, sf, tidyverse)

# Download the data directly from a URL and store it as an object
attacks <- read_csv("https://mpjashby.github.io/crimemappingdata/london_attacks.csv") |>
  st_as_sf(coords = c("longitude", "latitude"), crs = "EPSG:4326")

# Plot the map
ggplot(attacks) +
  annotation_map_tile(zoom = 0, progress = "none") + 
  geom_sf(size = 4)

😎 Use zoomin in annotation_map_tile()

# Load the R packages we need to analyse this data
pacman::p_load(ggspatial, sf, tidyverse)

# Download the data directly from a URL and store it as an object
attacks <- read_csv("https://mpjashby.github.io/crimemappingdata/london_attacks.csv") |>
  st_as_sf(coords = c("longitude", "latitude"), crs = "EPSG:4326")

# Plot the map
ggplot(attacks) +
  annotation_map_tile(zoomin = 0, progress = "none") + 
  geom_sf(size = 4)

🚫 Don’t forget to comment your code

pacman::p_load(ggspatial, sf, tidyverse)

attacks <- read_csv("https://mpjashby.github.io/crimemappingdata/london_attacks.csv") |>
  st_as_sf(coords = c("longitude", "latitude"), crs = "EPSG:4326")

ggplot(attacks) +
  annotation_map_tile(zoomin = 0, progress = "none") + 
  geom_sf(size = 4) +
  scale_x_continuous(expand = expansion(mult = 0.5)) +
  scale_y_continuous(expand = expansion(mult = 0.2)) +
  labs(
    title = "Fatal Terrorist Attacks in London Between 2010 and 2018.",
    caption = "Background map by OpenStreetMap"
  ) +
  theme_void()

😎 Comment your code

# Load the R packages we need to analyse this data
pacman::p_load(ggspatial, sf, tidyverse)

# Download the data directly from a URL and store it as an object
attacks <- read_csv("https://mpjashby.github.io/crimemappingdata/london_attacks.csv") |>
  st_as_sf(coords = c("longitude", "latitude"), crs = "EPSG:4326")

# Plot the map
ggplot(attacks) +
  annotation_map_tile(zoomin = 0, progress = "none") + 
  geom_sf(size = 4) +
  scale_x_continuous(expand = expansion(mult = 0.5)) +
  scale_y_continuous(expand = expansion(mult = 0.2)) +
  labs(
    title = "Fatal Terrorist Attacks in London Between 2010 and 2018.",
    caption = "Background map by OpenStreetMap"
  ) +
  theme_void()

Comments start with # and a space

🚫 Incorrect:

#This is a comment

😎 Correct:

# This is a comment

This is going to matter a lot later in the module

🚫 Don’t compress your code

# Load the R packages we need to analyse this data
pacman::p_load(ggspatial,sf,tidyverse)
# Download the data directly from a URL and store it as an object
attacks <- read_csv("https://mpjashby.github.io/crimemappingdata/london_attacks.csv") |>
  st_as_sf(coords=c("longitude","latitude"), crs="EPSG:4326")
# Plot the map
ggplot(attacks) +
  annotation_map_tile(zoomin=0,progress="none") + 
  geom_sf(size=4) +
  scale_x_continuous(expand=expansion(mult=0.5)) +
  scale_y_continuous(expand=expansion(mult=0.2)) +
  labs(
    title="Fatal Terrorist Attacks in London Between 2010 and 2018.",
    caption="Background map by OpenStreetMap"
  ) +
  theme_void()

🌬️ Let your code breathe

# Load the R packages we need to analyse this data
pacman::p_load(ggspatial, sf, tidyverse)

# Download the data directly from a URL and store it as an object
attacks <- read_csv("https://mpjashby.github.io/crimemappingdata/london_attacks.csv") |>
  st_as_sf(coords = c("longitude", "latitude"), crs = "EPSG:4326")

# Plot the map
ggplot(attacks) +
  annotation_map_tile(zoomin = 0, progress = "none") + 
  geom_sf(size = 4) +
  scale_x_continuous(expand = expansion(mult = 0.5)) +
  scale_y_continuous(expand = expansion(mult = 0.2)) +
  labs(
    title = "Fatal Terrorist Attacks in London Between 2010 and 2018.",
    caption = "Background map by OpenStreetMap"
  ) +
  theme_void()

quiz

The pipe operator |>

Lots of R code looks like this:

# This script counts the number of robberies on each day of the week in the
# first quarter of 2019

# Load robbery data
robbery1 <- read_csv("https://mpjashby.github.io/crimemappingdata/san_francisco_robbery.csv")

# Select only the columns we need
robbery2 <- select(robbery1, date_time)

# Filter only those offences that occurred in the first quarter of 2019
robbery3 <- filter(robbery2, as_date(date_time) <= ymd("2019-03-31"))

# Create a new weekday variable
robbery4 <- mutate(robbery3, weekday = wday(date_time, label = TRUE))

# Count how many offences occurred on each weekday
count(robbery4, weekday)

Lots of R code looks like this:

# This script counts the number of robberies on each day of the week in the
# first quarter of 2019

# Load robbery data
robbery1 <- read_csv("https://mpjashby.github.io/crimemappingdata/san_francisco_robbery.csv")

# Select only the columns we need
robbery2 <- select(robbery1, date_time)

# Filter only those offences that occurred in the first quarter of 2019
robbery3 <- filter(robbery2, as_date(date_time) <= ymd("2019-03-31"))

# Create a new weekday variable
robbery4 <- mutate(robbery3, weekday = wday(date_time, label = TRUE))

# Count how many offences occurred on each weekday
count(robbery4, weekday)

robbery1 is (a) created, (b) used once, and (c) never used again

Lots of R code looks like this:

# This script counts the number of robberies on each day of the week in the
# first quarter of 2019

# Load robbery data
robbery1 <- read_csv("https://mpjashby.github.io/crimemappingdata/san_francisco_robbery.csv")

# Select only the columns we need
robbery2 <- select(robbery1, date_time)

# Filter only those offences that occurred in the first quarter of 2019
robbery3 <- filter(robbery2, as_date(date_time) <= ymd("2019-03-31"))

# Create a new weekday variable
robbery4 <- mutate(robbery3, weekday = wday(date_time, label = TRUE))

# Count how many offences occurred on each weekday
count(robbery4, weekday)

The same is true with robbery2, robbery3 and robbery4

create + use once + never use again ▶️ no need to create object

Unnecessary objects:

make code longer ▶️ harder to read ▶️ harder to understand

increase risk of typo errors, e.g.

robbery3 <- filter(robbery2, as_date(date_time) <= ymd("2019-03-31"))

robbery4 <- mutate(robbary3, weekday = wday(date_time, label = TRUE))

make it easier to mix up objects, e.g.

robbery2 <- select(robbery1, date_time)

robbery3 <- filter(robbery2, as_date(date_time) <= ymd("2019-03-31"))

robbery4 <- mutate(robbery2, weekday = wday(date_time, label = TRUE))

create + use once + never use again ▶️ use the pipe

Instead of:

robbery1 <- read_csv("https://mpjashby.github.io/crimemappingdata/san_francisco_robbery.csv")

robbery2 <- select(robbery1, date_time)

Use this:

robbery_dates <- read_csv("https://mpjashby.github.io/crimemappingdata/san_francisco_robbery.csv") |> 
  select(date_time)
  • |> connects lines
  • first argument (robbery2) of second function not included
  • |> at end of line
  • every line after first indented by 2 spaces

Keep extending the pipeline until you have produced an object you need to keep

robbery_wday_count <- read_csv("https://mpjashby.github.io/crimemappingdata/san_francisco_robbery.csv") |> 
  select(date_time) |> 
  filter(as_date(date_time) <= ymd("2019-03-31")) |> 
  mutate(weekday = wday(date_time, label = TRUE)) |> 
  count(weekday)

gt::gt(robbery_wday_count)
weekday n
Sun 34
Mon 27
Tue 28
Wed 20
Thu 34
Fri 27
Sat 26

Read |> as “and then”

robbery_wday_count <- read_csv("https://mpjashby.github.io/crimemappingdata/san_francisco_robbery.csv") |> 
  select(date_time) |> 
  filter(as_date(date_time) <= ymd("2019-03-31")) |> 
  mutate(weekday = wday(date_time, label = TRUE)) |> 
  count(weekday)
  • “load the data and then

Read |> as “and then”

robbery_wday_count <- read_csv("https://mpjashby.github.io/crimemappingdata/san_francisco_robbery.csv") |> 
  select(date_time) |> 
  filter(as_date(date_time) <= ymd("2019-03-31")) |> 
  mutate(weekday = wday(date_time, label = TRUE)) |> 
  count(weekday)
  • “load the data and then
  • “… select the date_time column and then

Read |> as “and then”

robbery_wday_count <- read_csv("https://mpjashby.github.io/crimemappingdata/san_francisco_robbery.csv") |> 
  select(date_time) |> 
  filter(as_date(date_time) <= ymd("2019-03-31")) |> 
  mutate(weekday = wday(date_time, label = TRUE)) |> 
  count(weekday)
  • “load the data and then
  • “… select the date_time column and then
  • “… filter for dates on/before 31 March 2019 and then

Read |> as “and then”

robbery_wday_count <- read_csv("https://mpjashby.github.io/crimemappingdata/san_francisco_robbery.csv") |> 
  select(date_time) |> 
  filter(as_date(date_time) <= ymd("2019-03-31")) |> 
  mutate(weekday = wday(date_time, label = TRUE)) |> 
  count(weekday)
  • “load the data and then
  • “… select the date_time column and then
  • “… filter for dates on/before 31 March 2019 and then
  • “… extract weekday of each robbery and then

Read |> as “and then”

robbery_wday_count <- read_csv("https://mpjashby.github.io/crimemappingdata/san_francisco_robbery.csv") |> 
  select(date_time) |> 
  filter(as_date(date_time) <= ymd("2019-03-31")) |> 
  mutate(weekday = wday(date_time, label = TRUE)) |> 
  count(weekday)
  • “load the data and then
  • “… select the date_time column and then
  • “… filter for dates on/before 31 March 2019 and then
  • “… extract weekday of each robbery and then
  • “… count number of robberies each weekday”

⚠️ Don’t add a pipe |> to the final line

robbery_wday_count <- read_csv("https://mpjashby.github.io/crimemappingdata/san_francisco_robbery.csv") |> 
  select(date_time) |> 
  filter(as_date(date_time) <= ymd("2019-03-31")) |> 
  mutate(weekday = wday(date_time, label = TRUE)) |> 
  count(weekday) |> 
Error in parse(text = input): <text>:6:0: unexpected end of input
4:   mutate(weekday = wday(date_time, label = TRUE)) |> 
5:   count(weekday) |> 
  ^
robbery_wday_count <- read_csv("https://mpjashby.github.io/crimemappingdata/san_francisco_robbery.csv") |> 
  select(date_time) |> 
  filter(as_date(date_time) <= ymd("2019-03-31")) |> 
  mutate(weekday = wday(date_time, label = TRUE)) |> 
  count(weekday) |> 
  
nrow(robbery_wday_count)
Error in nrow(count(mutate(filter(select(read_csv("https://mpjashby.github.io/crimemappingdata/san_francisco_robbery.csv"), : unused argument (robbery_wday_count)

This week

  • 📖 complete chapters 3 and 4
  • 🧑‍💻 complete this week’s exercise
  • 👋 ask questions at any time